let rec repeat n foo x =
    if n = 0
    then x
    else foo (repeat (n - 1) foo x);;

repeat 10 ((+) 1) 0;;

let clip n =
    if n < 0 then 0
    else if n > 10 then 10
    else n;;

let clip_list_map = List.map clip;;
let rec clip_list_rec = function
    | [] -> []
    | h::t -> (clip h)::(clip_list_map t)

let budget total_money expenses = List.fold_left (fun acc n -> acc - n) total_money expenses;;
let _ = budget 100 [10; 20];;

let curry f x y = f (x, y);;
let uncurry f (x, y) = f x y;;
let add (x, y) = x + y;;
let add' = curry add;;
let _ = add' 1 2;;

let string_length_above3 = List.filter (fun s -> String.length s > 3)
let add1f = List.map ((+.) 1.)

let strint_join strs seq =
    match strs with
        | h::t -> List.fold_right (fun s acc -> acc ^ seq ^ s) t h
        | [] -> "";;

let _ = strint_join ["hello"; "world"] ",";;

let keys map = List.fold_left (fun lst (ele, _) -> if List.exists ((=) ele) lst then lst else ele::lst) [] map;;
let _ = keys [(1, 2); (1, 3); (2, 3)];;

let row_vec_add = List.map2 (+);;
let matrix_add = List.map2 row_vec_add;;

let _ = matrix_add [[1;2]; [3;4]] [[1;1]; [2;2]];;

let row_append = List.map2 List.append;;

let list_trans_and_append cur acc =
    let cur_trans = List.map (fun x -> [x]) cur in
    row_append cur_trans acc;;

let n_empty_list n =
    List.init n (fun _ -> []);;

let rec matrix_transposition mat =
    let len = List.length mat in
    let rec inner = function
    | [] -> n_empty_list len
    | h::t -> list_trans_and_append h (inner t) in
    inner mat;;

let _ = matrix_transposition [[1; 2; 3]; [4; 5; 6]; [7; 8; 9]];;

let list_product l0 l1 =
    let rec inner n l0 l1 =
    match (l0, l1) with
    | ([], _) -> n
    | (_, []) -> n
    | (h0::t0, h1::t1) -> inner (n + h0 * h1) t0 t1 in
    inner 0 l0 l1;;

let matrix_product m0 m1 =
    let m1t = matrix_transposition m1 in
    List.map (fun l0 -> List.map (fun l1 -> list_product l0 l1) m1t) m0;;

let _ = matrix_product [[1; 2]; [3; 4]] [[6; 7]; [8; 9]];;
